/* 
 * Copyright (c) 2012, Fromentin Xavier, Schnell Michaël, Dervin Cyrielle, Brabant Quentin
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *      * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *      * The names of its contributors may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Fromentin Xavier, Schnell Michaël, Dervin Cyrielle OR Brabant Quentin 
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package kameleon.gui.view;

import java.awt.BorderLayout;
import java.awt.Cursor;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

import kameleon.exception.FileReadingException;
import kameleon.exception.KameleonException;
import kameleon.gui.exception.UnknownKeyException;
import kameleon.gui.language.SwitchLanguage;
import kameleon.gui.model.FileInfo;
import kameleon.gui.model.Model;
import kameleon.gui.model.Observer;
import kameleon.gui.util.FileConstants;
import kameleon.gui.util.ImageUtility;
import kameleon.gui.util.LanguageConstants;
import kameleon.plugin.PlugInInfo;

/**
 * View showing the file format of the currently selected file.
 * The file format is displayed using the coloured picture of the 
 * format.
 * 
 * @author		Schnell Michaël
 * @version		1.0
 */
public class FormatView extends JPanel 
implements Observer, LanguageConstants, FileConstants {

	/**
	 * Needed to serialize this class.
	 * 
	 * @see		java.io.Serializable
	 */
	private static final long serialVersionUID = 6674276013071380986L ;

	/**
	 * Icon representing an unknown file format or that no file
	 * is currently selected.
	 */
	protected static final ImageIcon UNKNOWN_FORMAT_IMAGE = 
			getUnknownFormatIcon() ;

	/**
	 * Model of this view.
	 */
	protected Model model ;
	
	/**
	 * Component displaying the icon of the format.
	 */
	protected JLabel formatIcon ;
	
	/**
	 * Parent {@code JFrame} of this instance.
	 */
	protected JFrame container ;
	
	/**
	 * Plug-in information about the currently displayed format.
	 */
	protected PlugInInfo currentAnalyzer ;

	/**
	 * Builds an instance with the given model and parent.
	 * 
	 * @param	model
	 * 			model of this view
	 * 
	 * @param	container
	 * 			parent {@code JFrame} of this component
	 */
	public FormatView(Model model, JFrame container) {
		super() ;
		this.model = model ;
		this.model.addObserver(this) ;
		this.container = container ;
		this.currentAnalyzer = null ;
		this.build() ;
	}// FormatView(Model, JFrame)

	/**
	 * Builds the content of this view.
	 */
	private void build() {
		this.setBorder(BorderFactory.createTitledBorder("")) ; //$NON-NLS-1$
		this.setLayout(new BorderLayout()) ;

		this.formatIcon = new JLabel(UNKNOWN_FORMAT_IMAGE) ;
		this.formatIcon.addMouseListener(new FormatMouseListener()) ;
		this.add(this.formatIcon, BorderLayout.CENTER) ;
	}// build()

	/**
	 * Updates the displayed icon base on the currently selected file.
	 * 
	 * @throws	UnknownKeyException
	 * 			if a key needed for a displayed text was not found
	 * 
	 * @throws	FileReadingException
	 * 			if an icon could not be read
	 */
	@SuppressWarnings("null")
	@Override
	public void update() 
			throws FileReadingException, UnknownKeyException {
		// Update the format icon
		if (this.model.selectionHasChanged()) {
			// Update the cursor
			SwitchLanguage sl = SwitchLanguage.getInstance() ;
			
			// Determine the new icon and tooltip
			String newTooltip = null ;
			ImageIcon newIcon  = null ;
			int cursorType = Cursor.HAND_CURSOR ;
			FileInfo currentFile = this.model.getSelectedFileInfo() ;
			PlugInInfo newAnalyzer = null ;
			
			boolean formatIsUnknown = true ;
			if (currentFile != null) {
				newAnalyzer = this.model.getAnalyzer(
						currentFile.getIdFormat()) ;
				formatIsUnknown = (newAnalyzer == null) ;
			}// if
			
			if (formatIsUnknown) {
				newTooltip = sl.getText(UNKNOWN_FORMAT) ;
				newIcon = UNKNOWN_FORMAT_IMAGE ;
				cursorType = Cursor.HAND_CURSOR ;
				this.currentAnalyzer = null ;
			} else {
				// A new icon has to be loaded
				if (!newAnalyzer.equals(this.currentAnalyzer)) {
					newTooltip = newAnalyzer.getFormatName() ;
					newIcon = new ImageIcon(
							ImageUtility.getImageBytes(String.format(
									COLOR_ICON, newAnalyzer.getId()))) ;
					this.currentAnalyzer = newAnalyzer ;
				}// if
			}// if
			
			// Do the actual updating, if necessary
			if (newTooltip != null) {
				this.formatIcon.setIcon(newIcon) ;
				this.formatIcon.setToolTipText(newTooltip) ;
				this.formatIcon.setCursor(
						Cursor.getPredefinedCursor(cursorType)) ;
			}// if
		}// if
	}// update()

	/**
	 * Updates the text to match the currently selected language.
	 * 
	 * @throws 	UnknownKeyException
	 * 			if an error occurred while updating the text of this view
	 */
	@Override
	public void reloadLanguage() throws UnknownKeyException {
		SwitchLanguage sl = SwitchLanguage.getInstance() ;
		TitledBorder border = (TitledBorder) this.getBorder() ;
		border.setTitle(sl.getText(FORMAT_TITLE_BORDER)) ;
		if (!this.model.fileIsSelected() 
				|| (this.model.getCurrentFileFormat() == null)) {
			this.formatIcon.setToolTipText(
					sl.getText(LanguageConstants.UNKNOWN_FORMAT)) ;
		}// if
	}// reloadLanguage()

	/**
	 * Returns an instance of {@code ImageIcon} used to display an
	 * unknown format (or that no file is currently selected).
	 * 
	 * @return	Instance of {@code ImageIcon} used to display an
	 * 			unknown format
	 */
	protected static ImageIcon getUnknownFormatIcon() {
		InputStream src = null ;
		ImageIcon result = null ;
		try {
			src = new BufferedInputStream(
					SelectionView.class.getResourceAsStream(
							UNKNOWN_FORMAT_FILE)) ;
			result = new ImageIcon(ImageUtility.getImageBytes(src)) ;
			src.close() ;
		} catch (KameleonException ke) {
			//TODO Throw exception ?
			/* This should not happen. */
		} catch (IOException oie) {
			//TODO Handle exception
//			throw new FileReadingException(new File(UNKNOWN_FORMAT_FILE)) ;
		}// try
		return result ;
	}// getUnknownFormatIcon()

	/**
	 * Listener handling the clicks on the format icon. Displays
	 * the frame for the selection of the format for the currently
	 * selected file.
	 * 
	 * @author	Schnell Michaël
	 * @version	1.0
	 */
	private class FormatMouseListener extends MouseAdapter {
		
		/**
		 * Sole constructor.
		 */
		public FormatMouseListener() {
			super() ;
		}// FormatMouseListener()

		/**
		 * Opens the frame for the selection of the format for the 
		 * currently selected file, if possible.
		 */
		@Override
		public void mouseClicked(MouseEvent me) {
			if (FormatView.this.model.fileIsSelected()) {
				try {
					new EntryFormatSelectionFrame(
							FormatView.this.container, 
							FormatView.this.model).setVisible(true) ;
				} catch (KameleonException ex) {
					/* This should not happend ! */
					//TODO Add Handle in case is does !
				}// try
			}// if
		}// mouseClicked(MouseEvent)
		
	}// class FormatMouseListener

}// class FormatView